﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

using Microsoft.Practices.Unity;

using ERPStore.Extensions;
using System.Data.Entity.Core.Objects;

namespace ERPStore.QuoteCart.Repositories
{
	public class SqlQuoteCartRepository : CloudSoft.Repositories.SqlRepository<QuoteCartDbContext>
		, IQuoteCartRepository
	{
		private CloudSoft.Repositories.IDbContextFactory<QuoteCartDbContext> m_DbContextFactory;

        public SqlQuoteCartRepository(
			ERPStore.Services.ICacheService cacheService
			, ERPStore.Logging.ILogger logger
			, ERPStore.Services.IAccountService accountService
			, ERPStore.Services.IAddressService addressService
			, CloudSoft.Repositories.IDbContextFactory<QuoteCartDbContext> dbContextFactory)
		{
			this.CacheService = cacheService;
			this.Logger = logger;
			this.AccountService = accountService;
			this.AddressService = addressService;
			this.m_DbContextFactory = dbContextFactory;
		}

		protected ERPStore.Services.ICacheService CacheService { get; set; }
		protected ERPStore.Logging.ILogger Logger { get; set; }
		protected ERPStore.Services.ICatalogService CatalogService { get; private set; }
		protected ERPStore.Services.IAccountService AccountService { get; set; }
		protected ERPStore.Services.IAddressService AddressService { get; set; }

		public override QuoteCartDbContext GetDbContext()
		{
			return m_DbContextFactory.GetDbContext();
		}

		#region ICartRepository Members

		public IQueryable<Datas.QuoteCart> GetQuoteCartList()
		{
			var dbContext = GetDbContext();
			var list = from cartData in dbContext.QuoteCart.Include("Items")
					   where cartData.CartStateId != (int)Models.CartState.CanceledByUser
					   select cartData;
			return list;
		}

		public void Save(Models.QuoteCart cart, ERPStore.Models.UserPrincipal principal)
		{
            using (var db = GetDbContext())
			{
				var cartData = db.QuoteCart.FirstOrDefault(i => i.Code == cart.Code);
				if (cartData == null)
				{
					cartData = new Datas.QuoteCart();
					cartData.Code = cart.Code;
					cartData.CreationDate = DateTime.Now;
					cartData.CartStateId = (int)Models.CartState.CurrentQuote;
					db.QuoteCart.Add(cartData);
				}
				cartData.CustomerDocumentReference = cart.CustomerDocumentReference;
				cartData.CustomerPersonId = cart.CustomerId;
				cartData.LastUpdate = DateTime.Now;
				cartData.Message = cart.Message;
				cartData.VisitorId = cart.VisitorId;
				cartData.LastPage = cart.LastPage;
				cartData.LeadSourceInfo = cart.LeadSourceInfo;
				cartData.LeadSourceId = cart.LeadSourceId;

				if (principal.CurrentUser != null)
				{
					cartData.CustomerPersonId = principal.CurrentUser.Id;
					if (principal.CurrentUser.Corporate != null)
					{
						cartData.CustomerPersonId = principal.CurrentUser.Corporate.Id;
					}
				}

				if (cart.ConvertedEntityId.HasValue)
				{
					cartData.ConvertedEntityId = cart.ConvertedEntityId.Value;
					cartData.ConversionDate = DateTime.Now;
					cartData.CartStateId = (int)Models.CartState.ConvertedToQuote;
				}
                else
                {
                    cartData.ConvertedEntityId = cart.ConvertedEntityId;
                    cartData.ConversionDate = cart.ConversionDate;
                }

				var retryCount = 0;
retry:
				try
				{
					db.SaveChanges();
				}
				catch (System.Data.DBConcurrencyException oce)
				{
					((System.Data.Entity.Infrastructure.IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.ClientWins, cartData);
					Logger.Warn(oce.Message);
					retryCount++;
					if (retryCount < 3)
					{
						System.Threading.Thread.Sleep(100);
						goto retry;
					}
				}
				catch (System.Data.Entity.Validation.DbEntityValidationException ex)
				{
					foreach (var item in ex.EntityValidationErrors)
					{
						foreach (var error in item.ValidationErrors)
						{
							ex.Data.Add("SqlCartRepository.Save." + error.PropertyName, error.ErrorMessage);
						}
					}
					throw;
				}
				catch 
				{
					throw;
				}

				var cartItemList = db.QuoteCartItem.Where(i => i.QuoteCartId == cartData.Id && !i.IsArchived);

				foreach (var cartItem in cart.Items)
				{
					var cartItemData = cartItemList.SingleOrDefault(i => i.Id == cartItem.Id);
					if (cartItemData == null)
					{
						cartItemData = new Datas.QuoteCartItem();
						db.QuoteCartItem.Add(cartItemData);
						cartItemData.QuoteCartId = cartData.Id;
						cartItemData.ProductId = cartItem.Product.Id;
						cartItemData.CreationDate = cartItem.CreationDate;
					}
					cartItemData.LastUpdate = DateTime.Now;
					cartItemData.Quantity = cartItem.Quantity;

					cartItemData.AddFrom = cartItem.AddFrom;
					cartItemData.OfferName = cartItem.OfferName;
					cartItemData.InventoryTimeStateId = cartItem.InventoryTimeStateId;
				}

                try
                {
				    db.SaveChanges();
                }
                catch (System.Data.Entity.Validation.DbEntityValidationException ex)
                {
                    foreach (var item in ex.EntityValidationErrors)
                    {
                        foreach (var error in item.ValidationErrors)
                        {
                            ex.Data.Add("SqlCartRepository.Save." + error.PropertyName, error.ErrorMessage);
                        }
                    }
                    throw;
                }
                catch
                {
                    throw;
                }

				// Suppression des items
				var itemToDelete = cartItemList.ToList()
									.Select(i => i.ProductId)
									.Except(cart.Items.Select(i => i.Product.Id));

				foreach (var item in itemToDelete)
				{
					var cartItemData = cartItemList.Where(i => !i.IsArchived).First(i => i.ProductId == item);
					cartItemData.IsArchived = true;
				}

                try
                {
                    db.SaveChanges();
                }
                catch (System.Data.Entity.Validation.DbEntityValidationException ex)
                {
                    foreach (var item in ex.EntityValidationErrors)
                    {
                        foreach (var error in item.ValidationErrors)
                        {
                            ex.Data.Add("SqlCartRepository.Save." + error.PropertyName, error.ErrorMessage);
                        }
                    }
                    throw;
                }
                catch
                {
                    throw;
                }

			}
		}

		public void Remove(string code)
		{
			var cart = Get<Datas.QuoteCart>(i => i.Code == code);
			using (var db = GetDbContext())
			{
				var cartData = db.QuoteCart.FirstOrDefault(i => i.Code == cart.Code);
				if (cartData == null)
				{
					return;
				}
				cartData.CartStateId = (int)Models.CartState.CanceledByUser;
				db.SaveChanges();
			}
		}

		public void ChangeCurrent(string cartId, string visitorId)
		{
			var cartList = Query<Datas.QuoteCart>(i => i.VisitorId == visitorId);

			foreach (var cart in cartList)
			{
				// Par sécurité
				if (cart.ConvertedEntityId != null)
				{
					continue;
				}
				if (cart.Code.ToLower() == cartId.ToLower())
				{
					cart.CartStateId = (int)Models.CartState.CurrentQuote;
				}
				else
				{
					cart.CartStateId = (int)Models.CartState.Quote;
				}
				Update<Datas.QuoteCart>(cart);
			}

		}

		#endregion
	}
}
